/****************************************************************
 * <strong>MFExchange数据类型转换类</strong>
 *
 * <p>
 *MFExchange数据类型转换类
 * </p>
 *
 * @author AndyZhang 2011 cnet2001@163.com
 * @version 0.1
 * ToDo:2011-12-22
 ***************************************************************/

package com.thinkwide.data.exchange;

import com.thinkwide.data.core.MFRandom;
import com.thinkwide.data.ormapping.MFReflect;
import com.thinkwide.data.ormapping.annotation.MFField;
import com.thinkwide.data.ormapping.datatable.MFDataColumn;
import com.thinkwide.data.ormapping.datatable.MFDataColumnException;
import com.thinkwide.data.ormapping.datatable.MFDataRow;
import com.thinkwide.data.ormapping.datatable.MFDataTable;
import com.thinkwide.data.core.MFString;
import com.thinkwide.data.core.MFStringBuilder;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.sql.Blob;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

public class MFExchange {

    public static Map<String, String> getListToMap(List<String> list) {
        Map<String, String> map = new LinkedHashMap<String, String>();

        for (String item : list) {
            map.put(item, item);
        }

        return map;
    }

    public static Map<String, String> getTableToMap(MFDataTable dbTable, String keyField, String valueField) throws MFDataColumnException {
        Map<String, String> map = new LinkedHashMap<String, String>();

        for (MFDataRow item : dbTable.getRows()) {
            map.put(item.getString(keyField), item.getString(valueField));
        }

        return map;
    }

    public static List<String> getTableToList(MFDataTable dbTable, String valueField) throws MFDataColumnException {
        List<String> list = new ArrayList<String>();

        for (MFDataRow item : dbTable.getRows()) {
            list.add(item.getString(valueField));
        }

        return list;
    }


    public static List<String> getMapToList(Map<String, String> map, boolean needKey) {
        List<String> list = new ArrayList<String>();

        for (Map.Entry<String, String> item : map.entrySet()) {
            if (needKey) {
                list.add(item.getKey());
            } else {
                list.add(item.getValue());
            }
        }

        return list;
    }

    public static List<String> splitTextToList(String data, String split) {
        ArrayList<String> list = new ArrayList<String>();
        String[] str = data.split(split);
        for (String item : str) {
            if (MFString.notNullOrEmpty(item)) {
                list.add(item);
            }
        }

        return list;
    }

    public static List<String> getTextToList(String data) {
        ArrayList<String> list = new ArrayList<String>();
        String[] str = data.split(MFString.NewLine);
        for (String item : str) {
            if (MFString.notNullOrEmpty(item)) {
                list.add(item);
            }
        }

        return list;
    }

    public static String getListToText(List<String> list, String split) {
        MFStringBuilder sb = new MFStringBuilder();
        for (String item : list) {
            if (MFString.isNullOrEmpty(sb.toString())) {
                sb.append(item);
            } else {
                sb.append(split + item);
            }
        }

        return sb.toString();
    }

    public static List<String> getTextToList(String data, String split) {
        ArrayList<String> list = new ArrayList<String>();
        String[] str = data.split(split);
        for (String item : str) {
            if (MFString.notNullOrEmpty(item)) {
                list.add(item);
            }
        }

        return list;
    }

    /*
     * 默认换行符
     */
    public static String getListToText(List<String> list) {
        MFStringBuilder sb = new MFStringBuilder();
        for (String item : list) {
            sb.appendln(item);
        }
        return sb.toString();
    }

    public static Map<String, String> getTextToMap(String data, String split) {
        LinkedHashMap<String, String> map = new LinkedHashMap<String, String>();
        String[] str = data.split(MFString.NewLine);
        for (String item : str) {
            if (MFString.notNullOrEmpty(item)) {
                map.put(MFString.getStrName(item, split), MFString.getStrValue(item, split));
            }
        }


        return map;
    }

    public static String getMapToText(Map<String, String> map, String split) {
        MFStringBuilder sb = new MFStringBuilder();
        for (Map.Entry<String, String> item : map.entrySet()) {
            sb.appendln(item.getKey() + split + item.getValue());
        }
        return sb.toString();
    }

    public static <T> void SetEntity(Object Entity, MFDataRow row, List<String> names) throws Throwable {

        for (String name : names) {

            Object value = row.getValue(name);
            String relName = MFReflect.getRealPropertyName(Entity, name);
            if (MFString.notNullOrEmpty(relName)) {
                MFReflect.setDbProperty(Entity, relName, value);

            }
        }

    }

    public static <T> List<T> getDataTableToList(Class<T> classType, MFDataTable dataTable) throws Throwable {
        List<T> list = new ArrayList<T>();
        List<String> fields = dataTable.getColumns().getColumnNames();
        for (MFDataRow row : dataTable.getRows()) {
            T Entity = classType.newInstance();

            MFExchange.SetEntity(Entity, row, fields);

            list.add(Entity);
        }
        return list;
    }

    public static <T> MFDataTable getListToDataTable(Class<T> classType, List<T> list) throws Throwable {
        MFDataTable dataTable = new MFDataTable();
        List<Field> fieldList = MFReflect.getClassFields(classType, MFField.class);
        for (Field item : fieldList) {
            dataTable.addColumn(item.getName(), item.getName());
        }


        for (T item : list) {
            MFDataRow row = dataTable.newRow();
            int i = 0;
            for (MFDataColumn col : dataTable.getColumns()) {
                Object value = MFReflect.getProperty(item, col.getField());
                row.setValue(i, value);
                i++;
            }
        }

        return dataTable;
    }


    public static byte[] BlobToBytes(Blob blob) {
        BufferedInputStream is = null;

        try {
            is = new BufferedInputStream(blob.getBinaryStream());
            byte[] bytes = new byte[(int) blob.length()];
            int len = bytes.length;
            int offset = 0;
            int read = 0;

            while (offset < len && (read = is.read(bytes, offset, len - offset)) >= 0) {
                offset += read;
            }
            return bytes;
        } catch (Exception e) {
            return null;
        } finally {
            try {
                is.close();
                is = null;
            } catch (IOException e) {
                return null;
            }
        }
    }


    public static byte[] InputStreamToByte(InputStream is) throws IOException {

        ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
        int ch;

        while ((ch = is.read()) != -1) {
            bytestream.write(ch);
        }

        byte data[] = bytestream.toByteArray();
        bytestream.close();

        return data;

    }

    public static InputStream ByteToInputStream(byte[] bt) throws IOException {
        InputStream is = new ByteArrayInputStream(bt);
        return is;
    }

    public static <T> JSONObject getEntityToJson(T Entity) throws Throwable {
        List<String> ls = MFReflect.getPropertyList(Entity.getClass());

        JSONObject obj = new JSONObject();

        for (String name : ls) {
            Object value = obj.get(name);
            obj.put(name, MFReflect.getProperty(Entity, name));
        }

        return obj;
    }

    public static <T> void setJsonToEntity(JSONObject obj, T Entity) throws Throwable {
        List<String> ls = MFReflect.getPropertyList(Entity.getClass());
        String[] names = obj.getNames(obj);
        for (String name : names) {
            Object value = obj.get(name);
            if (MFString.notNullOrEmpty(name) && MFReflect.isHaveProperty(Entity, name)) {
                MFReflect.setDbProperty(Entity, name, value);
            }
        }
    }

    public static <T> List<T> getJsonToObjectList(Class<T> classType, JSONArray array) throws Throwable {
        List<T> list = new ArrayList<T>();
        for (int i = 0; i < array.length(); i++) {
            JSONObject obj = array.getJSONObject(i);
            T e = classType.newInstance();
            setJsonToEntity(obj, e);
            list.add(e);
        }

        return list;

    }

    public static JSONObject getDataTableToJson(MFDataTable table, Integer count) throws JSONException, MFDataColumnException {

        JSONArray objList = new JSONArray();

        JSONObject obj;
        for (MFDataRow r : table.getRows()) {
            obj = new JSONObject();
            for (MFDataColumn col : table.getColumns()) {
                obj.put(col.getField(), r.getString(col.getField()));
            }
            objList.put(obj);
        }

        obj = new JSONObject();
        obj.put("total", count);
        obj.put("root", objList);
        return obj;

    }


    public static MFDataTable getJsonToDataTable(String data, String tableName, String primaryField) throws MFDataColumnException, Throwable {
        MFDataTable table = new MFDataTable();
        JSONArray objList = new JSONArray(data);

        List<String> fields = new ArrayList<String>();
        if (objList.length() == 0) {
            return null;
        }

        JSONObject baseobj = objList.getJSONObject(0);
        Iterator it = baseobj.keys();
        while (it.hasNext()) {
            String keyname = (String) it.next();
            if ("mfstate".equals(keyname)) {
                continue;
            }

            table.addColumn(keyname);
            fields.add(keyname);
        }

        for (int i = 0; i < objList.length(); i++) {
            JSONObject obj = objList.getJSONObject(i);
            MFDataRow row = table.newRow();
            for (String field : fields) {
                row.setValue(field, obj.getString(field));
            }

            if ("modify".equals(obj.getString("mfstate"))) {
                row.setModifyState();
            } else {
                row.setInsertState();
                if (MFString.isNullOrEmpty(row.getString(primaryField))) {
                    row.setValue(primaryField, MFRandom.getNewGuid());
                }
            }
        }

        table.setPrimaryFields(primaryField);
        table.setTableName(tableName);
        return table;
    }

    public static List<String> getJsonFieldList(String data) throws JSONException {
        JSONArray array = new JSONArray(data);
        if (array.length() == 0) {
            return null;
        }

        List<String> list = new ArrayList<String>();

        JSONObject baseobj = array.getJSONObject(0);
        Iterator it = baseobj.keys();
        while (it.hasNext()) {
            String keyname = (String) it.next();
            if ("mfstate".equals(keyname)) {
                continue;
            }
            list.add(keyname);
        }
        return list;
    }


    public static String getJsonHFieldString(String jsonsource) throws JSONException {
        List<String> list = getJsonFieldList(jsonsource);
        StringBuffer sb = new StringBuffer();
        for (String s : list) {
            sb.append(s + ",");
        }
        return sb.toString();
    }

    public static MFDataTable getDataTableCharsetName(MFDataTable dbTable, String OldCharsetName, String newCharsetName) throws UnsupportedEncodingException, MFDataColumnException {
        for (MFDataRow row : dbTable.getRows()) {
            for (MFDataColumn col : dbTable.getColumns()) {
                if (row.getValue(col.getField()) != null) {
                    String datax = row.getString(col.getField());
                    datax = new String(datax.getBytes(OldCharsetName), newCharsetName);
                    row.setValue(col.getField(), datax);
                }
            }
        }

        return dbTable;
    }

}
